package rpc

import (
	"fmt"
	"github.com/docker/libkv/store"
	"github.com/smallnest/rpcx/client"
	"github.com/smallnest/rpcx/protocol"
	"time"
)

//EtcdDefaultCreator return a default ectd creator, it create client use failfast & random select & timeout = 15s
//it`s shorthand of EtcdCreator(15*time.Second, client.Failfast, client.RandomSelect, base, etcd)
func EtcdDefaultCreator(base, etcd string) func(string) (client.XClient, error) {
	return EtcdCreator(
		15*time.Second,
		client.Failfast,
		client.RandomSelect,
		base,
		etcd,
	)
}

//EtcdCreator return a default ectd creator
func EtcdCreator(
	timeout time.Duration,
	failmode client.FailMode,
	selectmode client.SelectMode,
	base string,
	etcds ...string,
) func(string) (client.XClient, error) {
	return func(name string) (c client.XClient, err error) {
		defer func() {
			if r := recover(); r != nil {
				err = fmt.Errorf("EtcdCreator create xclient: %v", r)
			}
		}()
		c = GetEtcdClient(name, timeout, failmode, selectmode, base, etcds...)
		return
	}
}

//PeerDefaultCreator call RawPeerDefaultCreator use getter return data[name]
func PeerDefaultCreator(data map[string]string) func(string) (client.XClient, error) {
	return RawPeerDefaultCreator(func(name string) string {
		return data[name]
	})
}

//RawPeerDefaultCreator return a default peer creator, it create client use failfast & random select & timeout = 15s
//it`s shorthand of PeerCreator(15*time.Second, client.Failfast, client.RandomSelect, getter)
func RawPeerDefaultCreator(getter func(string) string) func(string) (client.XClient, error) {
	return PeerCreator(
		15*time.Second,
		client.Failfast,
		client.RandomSelect,
		getter,
	)
}

//PeerCreator return a peer creator
func PeerCreator(
	timeout time.Duration,
	failmode client.FailMode,
	selectmode client.SelectMode,
	getter func(string) string,
) func(string) (client.XClient, error) {
	return func(name string) (c client.XClient, err error) {
		defer func() {
			if r := recover(); r != nil {
				err = fmt.Errorf("PeerCreator create xclient: %v", r)
			}
		}()
		c = GetPeerClient(name, timeout, failmode, selectmode, getter(name), "")
		return
	}
}

//GetClient return a default XClient
//it`s shorthand of GetEtcdClient(serviceName, 15s,Failfast,.RandomSelect,base,etcd)
func GetClient(serviceName string, base, etcd string) client.XClient {
	c := GetEtcdClient(serviceName,
		15*time.Second,
		client.Failfast,
		client.RandomSelect,
		base,
		etcd,
	)
	return c
}

//GetEtcdClient return a etcd XClient
func GetEtcdClient(
	serviceName string,
	timeout time.Duration,
	failmode client.FailMode,
	selectmode client.SelectMode,
	base string,
	etcds ...string,
) client.XClient {
	optionD := new(store.Config)
	optionD.ConnectionTimeout = timeout
	d := client.NewEtcdDiscovery(base, serviceName, etcds, optionD)
	option := client.DefaultOption
	option.Breaker = nil
	option.SerializeType = protocol.ProtoBuffer
	client := client.NewXClient(serviceName, failmode, selectmode, d, option)
	return client
}

//GetPeerClient return a peer XClient
func GetPeerClient(
	serviceName string,
	timeout time.Duration,
	failmode client.FailMode,
	selectmode client.SelectMode,
	port string,
	metaData string,
) client.XClient {
	d := client.NewPeer2PeerDiscovery("tcp@"+port, metaData)
	option := client.DefaultOption
	option.Breaker = nil
	option.SerializeType = protocol.ProtoBuffer
	client := client.NewXClient(serviceName, failmode, selectmode, d, option)
	return client
}
